//
//  DGGAliyunSignUtil.m
//  AliyunOSSiOS
//
//  Created by 胡中楷 on 2020/7/13.
//

#import "DGGAliyunSignUtil.h"
#import <CommonCrypto/CommonDigest.h>

@implementation DGGAliyunSignUtil

#pragma mark - POST请求签名
- (NSDictionary *)requestSignForPost:(NSDictionary *)requestParams sysKey:(NSString *)sysKey sysCode:(NSString *)sysCode{
    NSAssert(sysKey, @"sysKey is nil!");
    NSAssert(sysCode, @"sysCode is nil!");
    NSDate *date = [NSDate dateWithTimeIntervalSinceNow:0];//获取当前时间0秒后的时间
    NSString *timeSp = [self getRequestDateStr:date];
    NSString *nonce = [self getRequestNonceStr:date];
    NSString *requestStr = @"";
    if(requestParams){
        //验签注意，这里不能使用MJExtions提供的转json方法，会把空格去掉，而AFNetworking底层没有去掉空格，导致验签失败
        NSData *requestData = [NSJSONSerialization dataWithJSONObject:requestParams options:(NSJSONWritingPrettyPrinted) error:nil];
        requestStr = [[NSString alloc] initWithData:requestData encoding:NSUTF8StringEncoding];
    }
    NSMutableDictionary *signParams = @{}.mutableCopy;
    [signParams setValue:nonce forKey:@"nonce"];
    [signParams setValue:timeSp forKey:@"time"];
    [signParams setValue:[NSString stringWithFormat:@"%@",requestStr] forKey:@"data"];
    NSString *paramStr = [self signWithParams:signParams];
    NSString *signStr = [self createSign:paramStr sysKey:sysKey sysCode:sysCode];
    NSMutableDictionary *result = @{}.mutableCopy;
    [result setValue:[NSString stringWithFormat:@"%@", nonce] forKey:@"nonce"];
    [result setValue:[NSString stringWithFormat:@"%@", timeSp] forKey:@"time"];
    [result setValue:[NSString stringWithFormat:@"%@", signStr] forKey:@"sign"];
    [result setValue:[NSString stringWithFormat:@"%@", sysCode] forKey:@"sysCode"];
    [result setValue:@"true" forKey:@"replaceEmoji"];
    return result;
}

#pragma mark - GET请求签名
- (NSDictionary *)requestSignForGet:(NSString *)requestURL params:(NSDictionary *)params sysKey:(NSString *)sysKey sysCode:(NSString *)sysCode{
    NSMutableDictionary *requestParam = [self requestParamsWithURL:requestURL];
    if(params){
        [requestParam addEntriesFromDictionary:params];
    }
    NSDate *date = [NSDate dateWithTimeIntervalSinceNow:0];//获取当前时间0秒后的时间
    NSString *timeSp = [self getRequestDateStr:date];
    NSLog(@"请求时间：%@",timeSp);
    NSString *nonce = [self getRequestNonceStr:date];
    NSLog(@"请求ID：%@",nonce);
    NSString *requestStr = @"";
    if(requestParam){
        requestStr = [self signWithParams:requestParam];
        if(requestStr){
            requestStr = [requestStr stringByRemovingPercentEncoding];
        }
    }
    NSMutableDictionary *signParams = @{}.mutableCopy;
    [signParams setValue:nonce forKey:@"nonce"];
    [signParams setValue:timeSp forKey:@"time"];
    [signParams setValue:[NSString stringWithFormat:@"%@", requestStr] forKey:@"data"];
    NSString *handleSignStr = [self signWithParams:signParams];
    NSString *signStr = [self createSign:handleSignStr sysKey:sysKey sysCode:sysCode];
    NSMutableDictionary *result = @{}.mutableCopy;
    [result setValue:[NSString stringWithFormat:@"%@", nonce] forKey:@"nonce"];
    [result setValue:[NSString stringWithFormat:@"%@", timeSp] forKey:@"time"];
    [result setValue:[NSString stringWithFormat:@"%@", signStr] forKey:@"sign"];
    [result setValue:[NSString stringWithFormat:@"%@", sysCode] forKey:@"sysCode"];
    [result setValue:@"true" forKey:@"replaceEmoji"];
    return result;
}


#pragma mark - 排序拼接字符串
- (NSString *)signWithParams:(NSDictionary *)params{
    NSArray *keyArray = params.allKeys;
    NSStringCompareOptions comparisonOptions = NSCaseInsensitiveSearch|NSNumericSearch|NSWidthInsensitiveSearch|NSForcedOrderingSearch;
    NSComparator sort = ^(NSString *obj1,NSString *obj2){
        NSRange range =NSMakeRange(0,obj1.length);
        return [obj1 compare:obj2 options:comparisonOptions range:range];
    };
    NSLog(@"排序前：%@", keyArray);
    keyArray = [keyArray sortedArrayUsingComparator:sort];
    NSLog(@"排序后：%@", keyArray);
    NSMutableString *resultStr = [NSMutableString stringWithString:@""];
    NSInteger index = 0;
    for (NSString *key in keyArray) {
        NSString *value = params[key];
        //空值、空串不参与验签计算
        NSString *formatValue = @"";
        if(value && ![value isKindOfClass:([NSNull class])]){
            formatValue = [NSString stringWithFormat:@"%@", value];
        }
        if(value && ![formatValue isEqualToString:@""]){
            if(index > 0){
                [resultStr appendString:@"&"];
            }
            [resultStr appendFormat:@"%@=%@",key,value];
            index++;
        }
    }
    return resultStr;
}

- (NSString *)addCodeStr:(NSString *)sortString sysKey:(NSString *)sysKey sysCode:(NSString *)sysCode{
    NSMutableString *resultStr = [sortString mutableCopy];
    if(resultStr && sortString.length > 0){
        [resultStr appendString:@"&"];
    }
    [resultStr appendFormat:@"sysCode=%@", sysCode];
    [resultStr appendFormat:@"&secret=%@", sysKey];
    //过滤表情包
    NSString *filteredStr = [self filterEmoji:resultStr];
    return filteredStr;
}

- (NSString *)createSign:(NSString *)resultStr sysKey:(NSString *)sysKey sysCode:(NSString *)sysCode{
    NSString *sortASCIIString = [self addCodeStr:resultStr sysKey:sysKey sysCode:sysCode];
    //MD5加密,结果转换为大写字符
    NSString *sign = [[self MD5StringWithStr:sortASCIIString] uppercaseString];
    NSLog(@"签名前：%@\n签名后：%@", sortASCIIString, sign);
    return sign;
}

- (NSString *)MD5StringWithStr:(NSString *)contentStr{
    NSAssert(contentStr, @"string is nil!");
    const char *cStr = [contentStr UTF8String];
    unsigned char digest[CC_MD5_DIGEST_LENGTH];
    CC_MD5( cStr, (CC_LONG)strlen(cStr), digest );
    NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
    for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++){
        [output appendFormat:@"%02x", digest[i]];
    }
    return output;
}

- (NSString *)getRequestNonceStr:(NSDate *)date{
    NSString *result = @"";
    int num = (arc4random() % 10000000);
    NSString *randomNumber = [NSString stringWithFormat:@"%.4d", num];
    NSDateFormatter *dateformatter=[[NSDateFormatter alloc] init];
    [dateformatter setDateFormat:@"yyyyMMddHHmmssSSS"];
    NSString *timeStr = [dateformatter stringFromDate:date];
    timeStr = [timeStr stringByAppendingString:randomNumber];
    result = timeStr;
    return result;
}

- (NSString *)getRequestDateStr:(NSDate *)date{
    NSTimeInterval time = [date timeIntervalSince1970] * 1000;// *1000 是精确到毫秒，不乘就是精确到秒
    NSString *timeSp = [NSString stringWithFormat:@"%.0f", time];
    return timeSp;
}

#pragma mark - 过滤表情包
- (NSString *)filterEmoji:(NSString *)source {
    //去除表情
    NSRegularExpression* expression = [NSRegularExpression regularExpressionWithPattern:@"[^\\u0020-\\uD7FF\\uE000-\\uFFFD\\u10000-\\u10FFFF\\u0000\\u0009\\u000A\\u000D]" options:NSRegularExpressionCaseInsensitive error:nil];
    
    NSString* result = [expression stringByReplacingMatchesInString:source options:0 range:NSMakeRange(0, source.length) withTemplate:@""];
    return result;
}

#pragma mark - 通过URL解析参数
- (NSMutableDictionary *)requestParamsWithURL:(NSString *)requestURL{
    NSMutableDictionary *resultDC = @{}.mutableCopy;
    if(requestURL && [requestURL rangeOfString:@"?"].location != NSNotFound){
        NSString *paramsStr = [[requestURL componentsSeparatedByString:@"?"] lastObject];
        NSArray *paramsArray = [paramsStr componentsSeparatedByString:@"&"];
        for (NSString *param in paramsArray) {
            if(param && ![param isEqualToString:@""]){
                NSArray *keyValues = [param componentsSeparatedByString:@"="];
                if(keyValues.count > 0){
                    NSString *key = [keyValues firstObject];
                    NSString *value = @"";
                    if(keyValues.count > 1){
                        value = [keyValues lastObject];
                    }
                    [resultDC setValue:value forKey:key];
                }
            }
        }
    }
    return resultDC;
}

@end
